#include "buffer.h"
#include "errhandle.h"
#include "TagBuffer.h"
#include "memrec.h"
#define new DBG_NEW

tTagBuffer::tTagBuffer():
m_pFirstTag(NULL)
{
}


BYTE tTagBuffer::GetTagByte(const char * Tag, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{
		if (Length != 1)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return 0;
		}
		*Res = RET_OK;
		return GetByte();
	}
	*Res = RET_ERROR;
	return 0;
}


USHORT tTagBuffer::GetTagShort(const char * Tag, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		if (Length != 2)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return 0;
		}
		*Res = RET_OK;
		return GetShort();
	}
	*Res = RET_ERROR;
	return 0;
}


UINT tTagBuffer::GetTagInt24(const char * Tag, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		if (Length != 3)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return 0;
		}
		*Res = RET_OK;
		return GetInt3();
	}
	*Res = RET_ERROR;
	return 0;
}

UINT tTagBuffer::GetTagInt32(const char * Tag, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		if (Length != 4)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return 0;
		}
		*Res = RET_OK;
		return GetInt4();
	}
	*Res = RET_ERROR;
	return 0;
}

UINT64 tTagBuffer::GetTagInt64(const char * Tag, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		if (Length != 8)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return 0;
		}
		*Res = RET_OK;
		return GetInt8();
	}
	*Res = RET_ERROR;
	return 0;
}

tInt128	tTagBuffer::GetTagInt128(const char * Tag, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		if (Length != 16)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return 0;
		}
		*Res = RET_OK;
		return GetDataInt128();
	}
	*Res = RET_ERROR;
	return 0;
}


void tTagBuffer::GetTagData(const char * Tag, PBYTE pData, unsigned int pData_size, eResult * Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		if (Length != pData_size)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
			*Res = RET_ERROR;
			return;
		}
		*Res = RET_OK;
		GetData(pData, pData_size);
		return;
	}
	*Res = RET_ERROR;
	return;
}

void tTagBuffer::GetTagBuffer(const char * Tag, tBuffer * pBuf, eResult *Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		pBuf->refto(CurrentPointer(), Length);
		MovePointer(Length);
		*Res = RET_OK;
		return;
	}
	*Res = RET_ERROR;
	return;
}

unsigned int tTagBuffer::GetTagDataSize(const char * Tag, eResult *Res)
{
	unsigned int Length = 0;
	if (SearchTag(Tag, Length))
	{		
		// rollback.
		MoveBackPointer(TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE);
		*Res = RET_OK;
		return Length;
	}
	*Res = RET_ERROR;
	return 0;
}


void tTagBuffer::WriteTagByte(const char * Tag, BYTE v)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(1);
	tStreamBuffer::WriteByte(v);
}

void tTagBuffer::WriteTagShort(const char * Tag, USHORT v)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(2);
	tStreamBuffer::WriteShort(v);
}

void tTagBuffer::WriteTagInt24(const char * Tag, UINT v)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(3);
	tStreamBuffer::WriteInt3(v);
}

void tTagBuffer::WriteTagInt32(const char * Tag, UINT v)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(4);
	tStreamBuffer::WriteInt4(v);
}

void tTagBuffer::WriteTagInt64(const char * Tag, UINT64 v)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(8);
	tStreamBuffer::WriteInt8(v);
}

void tTagBuffer::WriteTagInt128(const char * Tag, tInt128 v)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(16);
	tStreamBuffer::WriteDataInt128(v);
}

void tTagBuffer::WriteTagData(const char * Tag, PBYTE ptr, unsigned int length)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(length);
	tStreamBuffer::Append(ptr, length);
}

void tTagBuffer::WriteEmptyTagData(const char * Tag, tBuffer * psb, unsigned int length)
{
	Append((PBYTE)Tag, 4);
	WriteInt4(length);
	psb->refto(CurrentPointer(), length);
	// We left the space for user to write its own data.
	MovePointer(length);
}

size_t tTagBuffer::ByteTagSize()
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + 1;
}

size_t tTagBuffer::ShortTagSize()
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + 2;
}

size_t tTagBuffer::Int24TagSize()
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + 3;
}

size_t tTagBuffer::Int32TagSize()
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + 4;
}

size_t tTagBuffer::Int64TagSize()
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + 8;
}
size_t tTagBuffer::Int128TagSize()
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + 16;
}

size_t tTagBuffer::DataTagSize(size_t DataSize)
{
	return TAG_NAME_FIELD_SIZE + DATA_LENGTH_FIELD_SIZE + DataSize;
}

void tTagBuffer::StartSearchTag()
{
	m_pFirstTag = NULL;//CurretnPointer();
}

bool tTagBuffer::NextTag()
{
	// If this first time to call NextTag(), directly return ture.
	if (m_pFirstTag == NULL)
	{
		if (Left() > 0)
			m_pFirstTag = CurrentPointer();
		else
		{
			ResetPointer();
			m_pFirstTag = CurrentPointer();
		}
		return true;
	}

	if (Left() > 0)
	{
		//Go to next tag if there is, if meet first tag, stop search.
		MovePointer(TAG_NAME_FIELD_SIZE);
		unsigned int length = GetInt4();
		MovePointer(length);
		if (CurrentPointer() == m_pFirstTag)
			return false;
	}
	
	if (Left() == 0)
	{
		// Go back to the head.
		ResetPointer();
		if (CurrentPointer() == m_pFirstTag)
			return false;
		else
			return true;
	}
	return true;
}

bool tTagBuffer::SearchTag(const char * Tag, unsigned int &length)
{
	StartSearchTag();
	while (NextTag())
	{
		char tag[TAG_NAME_FIELD_SIZE];
		tStreamBuffer::GetData((PBYTE)tag, TAG_NAME_FIELD_SIZE);
		if (memcmp(tag, Tag, TAG_NAME_FIELD_SIZE) != 0)
		{
			// rollback.
			MoveBackPointer(TAG_NAME_FIELD_SIZE);
			continue;
		}
		length = GetInt4();
		return true;
	}
	return false;
}
